package cz.possoft.integration.jbossmc;

import java.net.URL;

import org.jboss.dependency.spi.ControllerMode;
import org.jboss.dependency.spi.ControllerState;
import org.jboss.kernel.Kernel;
import org.jboss.kernel.plugins.bootstrap.AbstractBootstrap;
import org.jboss.kernel.plugins.bootstrap.basic.BasicBootstrap;
import org.jboss.kernel.plugins.deployment.xml.BasicXMLDeployer;
import org.jboss.kernel.spi.dependency.KernelController;
import org.jboss.kernel.spi.dependency.KernelControllerContext;

import cz.possoft.integration.ComponentManager;

/**
 * Implementation of component manager, which is based on JBoss Microcontainer.
 * 
 * @author mposolda
 */
public class JBossMCComponentManager implements ComponentManager {
	
	private static JBossMCComponentManager singleton;
	private static Object lock = new Object();
	
	Kernel kernel = null;
	BasicXMLDeployer deployer = null;
	
	
	
	private JBossMCComponentManager()
	{
		bootMicrocontainer();
		
		// deploy initial stuff
		try 
		{			
			URL possoftBeansXMLFileURL = Thread.currentThread().getContextClassLoader().getResource("jbossmc/possoft-beans.xml");
			deploy(possoftBeansXMLFileURL);
		}
		catch (Throwable t)
		{
			System.err.println("Error during deployment of JBoss microcontainer beans.");
			t.printStackTrace();
		}		
	}
	
	public static ComponentManager getInstance()
	{
		if (singleton == null)
		{
			synchronized(lock)
			{
				if (singleton == null)
				{
					singleton = new JBossMCComponentManager();
				}
			}
		}
		return singleton;		
	}
	
	/**
	 * Input should be class of interface and JBoss MC will return concrete implementation deployed in it.
	 * Component should be deployed in MC under the name of the interface, otherwise IllegalStateException will be thrown.
	 * 
	 * @throws IllegalStateException if component is not found or some other exception occured. 
	 */
	public <T extends Object> T getComponentInstanceByType(Class<T> clazz)
	{
			String className = clazz.getName();
			Object targetObject = getComponentInstanceByName(className);
			return clazz.cast(targetObject);
	}
	
	/**
	 * {@inheritDoc}
	 */
	public Object getComponentInstanceByName(String className)
	{
		KernelController controller = kernel.getController();
	    KernelControllerContext context = (KernelControllerContext) controller.getContext(className, ControllerState.INSTALLED);
	    if (context == null)
	    {
	    	throw new IllegalStateException("Component " + className + " not found at state 'installed' in JBoss Microcontainer.");
	    }
	    return context.getTarget();
	}
	
	/**
	 * {@inheritDoc}
	 */
	public void deploy(URL url) throws Throwable
	{
		deployer.deploy(url);
	}
	
	private void bootMicrocontainer()
	{
		AbstractBootstrap bootstrap = new BasicBootstrap();
		bootstrap.run();
		kernel = bootstrap.getKernel();
		deployer = new BasicXMLDeployer(kernel, ControllerMode.AUTOMATIC);
	}
	
}
